"""Copyright 2011 Thomas Anesta, Jonathan Brenner, Tyler Moylat, Rosa Tung, Sean Kim"""

"""

This file is part of Bubbles

Bubbles is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Bubbles is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

"""

import pygame, sys
import BubblesMap
import BubblesPlayer
import BubblesEnemies
import BubblesConstants
import BubblesShot
import BubblesPowerUp

Map = BubblesMap.Map
Player = BubblesPlayer.Player

class Game(object):
    def __init__(self):
        """initializes the game"""
        pygame.init()
        self.type = BubblesConstants.GAME_TYPE
        self.screen = pygame.display.set_mode((BubblesConstants.WINDOW_WIDTH, BubblesConstants.WINDOW_HEIGHT), pygame.FULLSCREEN)
        self.clock = pygame.time.Clock()
        self.numframes = 0
        self.map = BubblesMap.Map()
        self.player = BubblesPlayer.Player()
        self.waves = {}
        self.enemy = []
        self.powerups = []
        self.shots = []
        self.deaths = []
        self.player_is_firing = False
        self.shot_cooldown_counter = 0
        self.small_shot_cooldown = 4
        self.medium_shot_cooldown = 9
        self.large_shot_cooldown = 10
        self.score_font = pygame.font.Font(None, 32)
        self.score = [int(0)]
        
        self.health_image = pygame.image.load("gfx/L_Bubble_Shot.png").convert_alpha()

        self.boss_dead = False
        
    def process_events(self):
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    sys.exit()
                if event.key == pygame.K_UP:
                    self.player.moving[0] = True
                if event.key == pygame.K_DOWN:
                    self.player.moving[1] = True
                if event.key == pygame.K_LEFT:
                    self.player.moving[2] = True
                if event.key == pygame.K_RIGHT:
                    self.player.moving[3] = True
                if event.key == pygame.K_SPACE:
                    self.player_is_firing = True
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_UP:
                    self.player.moving[0] = False
                if event.key == pygame.K_DOWN:
                    self.player.moving[1] = False
                if event.key == pygame.K_LEFT:
                    self.player.moving[2] = False
                if event.key == pygame.K_RIGHT:
                    self.player.moving[3] = False
                if event.key == pygame.K_SPACE:
                    self.player_is_firing = False
        
        
    def update(self):
        self.map.update()
        self.player.update()
        self.shot_update()

        player_is_hit = int(0)
        for enemy in self.enemy:
            update_val = enemy.update(self.shots, self.player, self.score)
            if update_val == BubblesConstants.COLLISION_PLAYER_RETURN:
                #self.endgame()
                val = self.player.take_damage(1)#if dead sets to dead
                if val <= int(0):
                    self.deaths.append(self.player)
                
        for i, powerup in enumerate(self.powerups):
            returnval = powerup.update(self.player)
            if returnval == BubblesConstants.NO_COLLISION_RETURN:
                pass
            elif returnval == BubblesConstants.COLLISION_PLAYER_RETURN:
                self.player.powerup(powerup.offset)
                self.powerups[i].kill()
            elif returnval == BubblesConstants.OFF_SCREEN_RETURN:
                self.powerups[i].leave()
        
        #clean up
        for i, powerup in enumerate(self.powerups):
            if powerup.status != BubblesConstants.STATUS_ACTIVE:
                del self.powerups[i]
        
        
        for i, enemy in enumerate(self.enemy):
            if enemy.status == BubblesConstants.STATUS_ACTIVE:
                pass#do nothing
            elif enemy.status == BubblesConstants.STATUS_OFFSCREEN:
                del self.enemy[i]
            else:#then dead
                if enemy.type == BubblesConstants.SATELLITE_TYPE:
                    self.boss_dead = True
                    self.endgame()
                val = enemy.get_powerup()
                if val == BubblesConstants.POWERUP_NONE:
                    pass
                elif val == BubblesConstants.POWERUP_POSITIVE:
                    self.powerups.append(BubblesPowerUp.PowerUp(enemy.rect.centerx, enemy.rect.centery, BubblesPowerUp.get_rand_offset()))
                elif val == BubblesConstants.POWERUP_NEGATIVE:
                    self.powerups.append(BubblesPowerUp.PowerUp(enemy.rect.centerx, enemy.rect.centery, (BubblesPowerUp.get_rand_offset()*-1)))
                self.deaths.append(self.enemy[i])
                del self.enemy[i]
                
        for i, deathval in enumerate(self.deaths):
            if (deathval.frames - deathval.hit_frame) >= deathval.death_frames:
                del self.deaths[i]
        if (self.player.status == BubblesConstants.STATUS_DEAD) and (len(self.deaths) == 0):
            self.endgame()
        
    def shot_update(self):   
        """updates the shots on screen and deletes them when they leave the screen adjusts shot cooldown based on player size"""
        if self.player.size < 0:
            if self.player_is_firing and self.shot_cooldown_counter <= 0:
                self.fire()
                self.shot_cooldown_counter = self.small_shot_cooldown
        elif self.player.size == 0:
            if self.player_is_firing and self.shot_cooldown_counter <= 0:
                self.fire()
                self.shot_cooldown_counter = self.medium_shot_cooldown
        elif self.player.size > 0:
            if self.player_is_firing and self.shot_cooldown_counter <= 0:
                self.fire()
                self.shot_cooldown_counter = self.large_shot_cooldown
        
        for shot in self.shots:
            shot.update()
        for i, shot in enumerate(self.shots):
            if shot.rect.bottom > BubblesConstants.WINDOW_HEIGHT or shot.active == False:
                del self.shots[i]
        
        self.shot_cooldown_counter -= 1
    
    def draw(self):
        self.map.draw(self.screen)
        self.player.draw(self.screen)
        for enemy in self.enemy:
            enemy.draw(self.screen)
        for shot in self.shots:
            shot.draw(self.screen)
        for powerup in self.powerups:
            powerup.draw(self.screen)
        for death in self.deaths:
            death.draw_death(self.screen)
            
        pygame.draw.rect(self.screen, (0,0,0), (0, (BubblesConstants.WINDOW_HEIGHT - self.score_font.get_height() ), BubblesConstants.WINDOW_WIDTH, (self.score_font.get_height() + 5)))
        for hval in range(self.player.health):
            rect = self.health_image.get_rect()
            rect.x = BubblesConstants.WINDOW_WIDTH - (rect.width * (hval + 1))
            rect.y = BubblesConstants.WINDOW_HEIGHT - rect.height
            self.screen.blit(self.health_image, rect)
        score_surf = self.score_font.render(str(self.score[0]), 0, (255, 255, 255))
        score_rect = score_surf.get_rect()
        score_rect.x = 0
        score_rect.y = BubblesConstants.WINDOW_HEIGHT - self.score_font.get_height()
        self.screen.blit(score_surf, score_rect)
       
    def scroll_intro(self, text):
        ticks = 0
        separation = 10
        distance = 2
        travel = 500
        location = 1000
        tlength = len(text)
        maxticks= tlength * separation + travel
        display = {}#list of items on the display
        thefont = pygame.font.Font(None, 25)
        while ticks < maxticks:
        #do the clock thing
            self.clock.tick(30)
            events = pygame.event.get()
            for event in events:
                if event.type == pygame.KEYDOWN:
                    return
            self.screen.fill((0, 0, 0))
            curindex = ticks/separation
            if curindex < tlength:
                test = text[curindex]
                if test not in display:
                    val = test
                    display[val] = location
                    
                
            for item in display:
                display[item] = display[item] - distance
                textsurf = thefont.render(item, 0, (255, 255, 255))
                textrect = textsurf.get_rect()
                textrect.center = (320, display[item])
                self.screen.blit(textsurf, textrect)
            
            
            pygame.display.flip()
            ticks = ticks + 1

    def fire(self):
        """creates the projectile"""
        # rapid fire
        if self.player.size < BubblesPlayer.BUBBLE_MIN_NORMAL_SIZE:
            self.shots.append(BubblesShot.Shot(self.player.rect.centerx - 5, self.player.rect.top, 0, -20, 0, self.player))
        # spread shot
        elif self.player.size > BubblesPlayer.BUBBLE_MAX_NORMAL_SIZE:
            self.shots.append(BubblesShot.Shot(self.player.rect.left + 12, self.player.rect.top, -10, -20, 0, self.player))
            self.shots.append(BubblesShot.Shot(self.player.rect.right - 22, self.player.rect.top, 10, -20, 0, self.player))
            self.shots.append(BubblesShot.Shot(self.player.rect.centerx - 10, self.player.rect.top, -3, -20, 0, self.player))
            self.shots.append(BubblesShot.Shot(self.player.rect.centerx, self.player.rect.top, 3, -20, 0, self.player))
        # double shot
        else:
            self.shots.append(BubblesShot.Shot(self.player.rect.centerx - (5 + BubblesShot.SHOT_M_WIDTH), self.player.rect.top - BubblesShot.SHOT_M_HEIGHT, 0, -20, 0, self.player))
            self.shots.append(BubblesShot.Shot(self.player.rect.centerx + 5, self.player.rect.top - BubblesShot.SHOT_M_HEIGHT, 0, -20, 0, self.player))
            
    def populate_waves(self, waves):#as text
        wave = []
        wave_frame = -1
        wave_index = 0
        while wave_index < len(waves):
            if waves[wave_index][0] == "BEGIN_WAVE":
                wave = []
                wave_frame = int(waves[wave_index][1])
            elif waves[wave_index][0] == BubblesConstants.BEE_TYPE:
                wave.append(BubblesEnemies.Bee(int(waves[wave_index][1]), int(waves[wave_index][2])))
            elif waves[wave_index][0] == BubblesConstants.DRAGONFLY_TYPE:
                wave.append(BubblesEnemies.Dragonfly(int(waves[wave_index][1]), int(waves[wave_index][2])))
            elif waves[wave_index][0] == BubblesConstants.MOSQUITO_TYPE:
                wave.append(BubblesEnemies.Mosquito(int(waves[wave_index][1]), int(waves[wave_index][2])))
            elif waves[wave_index][0] == BubblesConstants.SATELLITE_TYPE:
                wave.append(BubblesEnemies.Satellite(int(waves[wave_index][1]), int(waves[wave_index][2])))
            elif waves[wave_index][0] == "END_WAVE":
                self.waves[wave_frame]=wave
            elif waves[wave_index][0] == "END_INPUT":
                break
            wave_index = wave_index + 1
            
    def endgame(self):
        lose = pygame.image.load("gfx/lose.png").convert_alpha()
        win = pygame.image.load("gfx/win.png").convert_alpha()
        del self.player
        pygame.draw.rect(self.screen, (0,0,0), pygame.Rect(0,0,BubblesConstants.WINDOW_WIDTH,BubblesConstants.WINDOW_HEIGHT))
        if self.boss_dead == True:
            self.screen.blit(win, pygame.Rect(0,0,BubblesConstants.WINDOW_WIDTH,BubblesConstants.WINDOW_HEIGHT))
        else:
            self.screen.blit(lose,pygame.Rect(0,0,BubblesConstants.WINDOW_WIDTH,BubblesConstants.WINDOW_HEIGHT))
        pygame.display.flip()
        pygame.time.delay(100)
        quit()

    def next_frame(self):
        if self.waves.has_key(self.numframes):
            for enemy in self.waves[self.numframes]:
                self.enemy.append(enemy)
        self.clock.tick(30)
        self.numframes = self.numframes + 1

